/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const { execSync } = require('child_process');
const os = require('os');

const IPV4_REGEX = /^\d+\.\d+\.\d+\.\d+$/;
const LOOPBACK_PREFIX = '127.';
let headerServerFlag: boolean = false;

function pickValidIp(candidates: string[] = []): string | undefined {
  return candidates
    .map(ip => ip?.trim())
    .find(ip => ip && !ip.startsWith(LOOPBACK_PREFIX) && IPV4_REGEX.test(ip));
}

function safeExec(command: string): string | undefined {
  try {
    return execSync(command, { encoding: 'utf8', shell: true }).trim();
  } catch {
    return undefined;
  }
}

function getIpFromInterfaces(): string | undefined {
  try {
    const interfaces = os.networkInterfaces();
    for (const iface of Object.values(interfaces)) {
      if (!iface) {
        continue;
      }
      const hit = iface.find(info => info.family === 'IPv4' && !info.internal);
      if (hit) {
        return hit.address;
      }
    }
  } catch (err) {
    console.error('Failed to get network IP from interfaces:', err);
  }
  return undefined;
}

function getIpFromWindowsCommand(): string | undefined {
  const output = safeExec('for /f "tokens=2 delims=:" %a in (\'ipconfig ^| findstr /i "IPv4"\') do @echo %a');
  return output ? pickValidIp(output.split('\n')) : undefined;
}

function getIpFromUnixCommands(): string | undefined {
  const hostnameResult = safeExec('hostname -I');
  const hostnameIp = hostnameResult ? pickValidIp(hostnameResult.split(/\s+/)) : undefined;
  if (hostnameIp) {
    return hostnameIp;
  }

  const ipCommandResult = safeExec("ip -4 addr show | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}'");
  return ipCommandResult ? pickValidIp(ipCommandResult.split(/\s+/)) : undefined;
}

function getIpFromSystemCommands(): string | undefined {
  try {
    return os.platform() === 'win32' ? getIpFromWindowsCommand() : getIpFromUnixCommands();
  } catch (err) {
    console.error('Failed to get IP via system command:', err);
    return undefined;
  }
}

/**
 * Get local network IP address
 * Returns the first non-internal IPv4 address found
 */
export function getLocalNetworkIP(): string {
  const sources = [getIpFromInterfaces, getIpFromSystemCommands];
  for (const source of sources) {
    const ip = source();
    if (ip) {
      return ip;
    }
  }

  // Ultimate fallback
  return '127.0.0.1';
}

/**
 * Install server dependencies
 */
export function installServer() {
  try {
    const result = execSync('npm i', {cwd: './LocalServer', encoding: 'utf8' });
    console.log(result);
  } catch (err) {
    console.error('Execution failed:', err.message);
  }
}

/**
 * Start header server
 */
export function startHeaderServer() {
  try {
    headerServerFlag = true;
    const result = execSync('npm run forever:start', {cwd: './LocalServer', encoding: 'utf8' });
    console.log(result);
  } catch (err) {
    console.error('Execution failed:', err.message);
  }
}

/**
 * Restart header server
 */
export function restartHeaderServer() {
  try {
    const result = execSync('npm run forever:restart', {cwd: './LocalServer', encoding: 'utf8' });
    console.log(result);
  } catch (err) {
    console.error('Execution failed:', err.message);
  }
}

/**
 * Stop header server
 */
export function stopHeaderServer() {
  try {
    headerServerFlag = false;
    const result = execSync('npm run forever:stop', {cwd: './LocalServer', encoding: 'utf8' });
    console.log(result);
  } catch (err) {
    console.error('Execution failed:', err.message);
  }
}

// ==================== Combined task ====================

/**
 * Start the header server task
 * Includes: installing dependencies, starting the server
 */
export function runHeaderTask() {
  try {
    const localIP = getLocalNetworkIP();
    console.log(`\n=== Header Server Configuration ===`);
    console.log(`Local Network IP: ${localIP}`);
    console.log(`Server URL: http://${localIP}:8081/api/headers`);
    console.log(`Please ensure your device is on the same network and use this IP in the app.\n`);
    
    if (!headerServerFlag) {
      installServer();
      startHeaderServer();
    } else {
      restartHeaderServer();
    }
  } catch (err) {
    console.error('Execution failed:', err.message);
  }
}

/**
 * Restart the header server task
 * Includes: restarting the server
 */
export function rerunHeaderTask() {
  try {
    const localIP = getLocalNetworkIP();
    console.log(`\n=== Header Server Configuration ===`);
    console.log(`Local Network IP: ${localIP}`);
    console.log(`Server URL: http://${localIP}:8081/api/headers`);
    console.log(`Please ensure your device is on the same network and use this IP in the app.\n`);
    
    restartHeaderServer();
  } catch (err) {
    console.error('Execution failed:', err.message);
  }
}

/**
 * Stop the header server task
 * Includes: stopping the server
 */
export function stopHeaderTask() {
  try {
    stopHeaderServer();
  } catch (err) {
    console.error('Execution failed:', err.message);
  }
}